package toolx

import (
	"fmt"

	"gitee.com/workits/pkgs/configx"
	"gitee.com/workits/pkgs/dbx"
	"gitee.com/workits/pkgs/utilx"
	"github.com/fsgo/go_fmt/gofmtapi"
)

// GenCode 生成代码
func GenCode(projDir, moduleName, tableName, tableComment, ignorePrefix, structName string) {
	genFiles := make([]string, 0)
	// 错误处理
	defer func() {
		if err := recover(); err != nil {
			for _, genFile := range genFiles {
				_ = utilx.FsRemove(genFile, true)
			}

			if err == ErrExist {
				panic(fmt.Sprintf("🔔已存在表%s生成的代码", tableName))
			}

			panic(err)
		}
	}()

	// 判断模块是否存在
	if !utilx.FsIsExist(projDir + PS + "internal" + PS + "app" + PS + moduleName) {
		panic("🔔模块不存在, 请先创建模块")
	}

	// 读取配置文件
	var wkcfg WkCfg
	if _, err := configx.UnmarshalFiles(projDir+PS+".workits", &wkcfg); err != nil {
		panic("🙅配置文件读取失败")
	}
	if len(tableComment) == 0 && wkcfg.DB.Dialect == "sqlite" {
		panic("🔔数据库表注释不能为空, 请使用 -c commentName")
	}

	// 查询表信息
	dbTool := NewDBTool(dbx.Config{
		Alias:   "default",
		Driver:  wkcfg.DB.Driver,
		Dialect: wkcfg.DB.Dialect,
		DSN:     wkcfg.DB.DSN(),
	})

	// 构造模版数据
	data := dbTool.TableToStructInfo(wkcfg.DB.Name, tableName, ignorePrefix, structName, true)
	if len(tableComment) > 0 {
		data.Comment = tableComment
	}
	data.GoModule = wkcfg.GoModule
	data.ProjModule = moduleName
	data.ModName = UderscoreToUpperCamelCase(data.ProjModule)

	// 生成文件并格式化
	genFiles = append(genFiles, GenerateFile(projDir, "entity", data))
	genFiles = append(genFiles, GenerateFile(projDir, "model", data))
	genFiles = append(genFiles, GenerateFile(projDir, "handler", data))
	genFiles = append(genFiles, GenerateFile(projDir, "router", data)) // TODO for http
}

// GenerateFile 生成文件
func GenerateFile(projDir, typ string, data StructInfo) string {
	// 参数解析
	var fPath, fName, tplDir, tplName string
	fPath = projDir + PS + "internal" + PS + "app" + PS + data.ProjModule + PS
	tplDir = projDir + PS + ".workits" + PS + "templates" + PS
	switch typ {
	case "entity":
		fName = fPath + "entity" + PS + data.FileName + "_entity.go"
		tplName = tplDir + "func.entity.go.tpl"
	case "model":
		fName = fPath + "model" + PS + data.FileName + "_model.go"
		tplName = tplDir + "func.model.go.tpl"
	case "handler":
		fName = fPath + "handler" + PS + data.FileName + "_handler.go"
		tplName = tplDir + "func.handler.go.tpl"
	case "router":
		fName = fPath + "component" + PS + "router" + PS + data.FileName + "_router.go"
		tplName = tplDir + "router_handler.go.tpl"
	}

	if utilx.FsIsExist(fName) {
		panic(ErrExist)
	}
	// 生成文件
	ParseTemplate(tplName, fName, data)

	// 格式化文件
	opts := gofmtapi.NewOptions()
	opts.Files = []string{fName}
	if err := gofmtapi.NewFormatter().Execute(opts); err != nil {
		panic(fmt.Sprintf("🙅文件%s格式化失败", fName))
	}

	return fName
}
